from django.dispatch import receiver
from django.db.models.signals import post_delete,post_save,pre_save
from django.contrib.auth import get_user_model
from django.template.loader import render_to_string

from backend.cews.services import RepairService
from backend.cews.services import emailService as EmailService
from backend.cews.services.VersionService import create_part_version, create_version_master, update_version_master,create_repair_order_part_version
from backend.eform.models import Eform
from backend.cews.models import PartVersion, Parts, RepairOrderPart, RepairOrderPartVersion, RepairOrderTask, StockItem, VersionMaster, Log, RepairOrder
from logger.createlogger import create_logger
from backend.eform.signals import eform_done_signal,eform_save_signal,eform_verify_signal,eform_endorse_signal
from django.db import transaction
from schema.eform_schema import EformStatusData
import json
User = get_user_model()

logger = create_logger('CEWSSignal')


def get_eform_status(data: EformStatusData):
    na_string = 'N/A'

    if data.endorsment_result == data.fail_string:
        return data.fail_string
    
    if data.verify_sic_resulta == data.fail_string:
        return data.fail_string

    if data.overall_test_result == data.fail_string:
        return data.fail_string
    
    if data.is_endorse_required:
        if data.doneDate != None and data.verifiedDate != None and data.endorsedDate != None :
            return data.pass_string
        else:
            return na_string
    
    if data.doneDate != None:
        return data.pass_string
    else:
        return na_string
    

def getEformStatus(eform:Eform):

    pass_string = eform.overall_test_result_choices[0][1]
    fail_string = eform.overall_test_result_choices[1][1]
    na_string = 'N/A'
    ## if failed, return failed
    if eform.overall_test_result == fail_string:
        return eform.overall_test_result
    
    ## if endorsed, return endorsed and must be overall test result pass
    if eform.is_endorse_required:
        if eform.doneDate != None and eform.verifiedDate != None and eform.endorsedDate != None :
            return pass_string
        else:
            return na_string
    
    if eform.doneDate != None:
        return pass_string
    else:
        return na_string
    
    return na_string
    

def check_repair_order_status(validata_list:list, rots_list:list) -> str:
    """取所有里最小的 done < verify < endorse, 通过则返回None
    """
    if (len(validata_list) == 0) or (len(rots_list) ==0):
        return None
    attr_value, status = validata_list.pop()
    for rot_obj in rots_list:
        if rot_obj.is_endorse_required:
            # 三种都要验证
            if getattr(rot_obj, attr_value, None) == None:
                return status
        else:
            if rot_obj.done_by_id == None:
                return RepairOrder.STATUS.IN_PROCESS
    return check_repair_order_status(validata_list, rots_list)


def check_repair_order_task(rot:RepairOrderTask, deleted = False) -> str:
    if deleted:
        rots_list = []
    else:
        rots_list = [rot]

    rots_queryset = RepairOrderTask.objects.filter(stock_code=rot.stock_code,serial_no=rot.serial_no, deleted=False, repair_order=rot.repair_order, repair_order_part=rot.repair_order_part).values_list("id","cur_tab", "final_tab", "endorse_by_id", "verify_by_id", "done_by_id", "role","is_endorse_required", named=True)
    for rot_obj in rots_queryset:
        if rot_obj.id != rot.id:
            if ((rot_obj.cur_tab) and (rot_obj.role == RepairOrderTask.RoleType.TESTER)) or (rot_obj.final_tab) and (rot_obj.role == RepairOrderTask.RoleType.CHECKER):
                rots_list.append(rot_obj)

    validata_list = [
        ("endorse_by_id", RepairOrder.STATUS.WAITING_FOR_ENDORSEMENT ),
        ("verify_by_id", RepairOrder.STATUS.WAITING_FOR_SIC ),
        ("done_by_id", RepairOrder.STATUS.IN_PROCESS ),
    ]

    if status := check_repair_order_status(validata_list, rots_list):
        return status

    return RepairOrder.STATUS.WAITING_FOR_JOB_COMPLETED


def handle_eform_save(eform:Eform):
    rots = RepairOrderTask.objects.filter(eform_id=eform.id)
    rot = rots.first()
    

    if rot:
        rot.eform_progress = eform.getProgress
        eform_data = EformStatusData(
            pass_string=eform.overall_test_result_choices[0][1],
            fail_string=eform.overall_test_result_choices[1][1],
            overall_test_result=eform.overall_test_result,
            verify_sic_resulta=eform.verify_sic_resulta,
            endorsment_result=eform.endorsment_result,
            is_endorse_required=eform.is_endorse_required,
            verifiedDate=eform.verifiedDate,
            endorsedDate=eform.endorsedDate, 
            doneDate=eform.doneDate,
        )
            
        if rot.role == RepairOrderTask.RoleType.CHECKER:
            flow = None
            if (rot.verify_by_id != eform.verifiedby_id):
                flow = "verified"
            if (rot.endorse_by_id != eform.endorsedby_id):
                flow = "endorsed"
            if flow:
                user = rot.create_user
                if user and user.email and user.enable_email:
                    email_message =  f"Your  Task {rot.name} had {flow} in Job {rot.repair_order.order_no}" 
                    EmailService.send_email(user.email,"CEWS EFORM Check", email_message) # 需要修改成真正的邮箱

        ## user id 
        rot.done_by_id = eform.doneby_id
        rot.verify_by_id = eform.verifiedby_id
        rot.endorse_by_id = eform.endorsedby_id
        
        rot.done_by_datetime = eform.doneDate
        rot.verify_by_datetime = eform.verifiedDate
        rot.endorse_by_datetime = eform.endorsedDate
        if rot.role == RepairOrderTask.RoleType.TESTER:
            rot.is_endorse_required = False
            eform_data.is_endorse_required = False
        else:
            rot.is_endorse_required = eform.is_endorse_required
        
        rot.role_result = get_eform_status(eform_data)
        repair_order = rot.repair_order
        repair_order_part = rot.repair_order_part

        doneDate = eform.doneDate
        verifiedDate = eform.verifiedDate
        endorsedDate = eform.endorsedDate

        if doneDate is not None:
            doneDate = eform.doneDate.strftime("%Y-%m-%d %H:%M:%S")

        if verifiedDate is not None:
            verifiedDate = eform.verifiedDate.strftime("%Y-%m-%d %H:%M:%S")

        if endorsedDate is not None:
            endorsedDate = eform.endorsedDate.strftime("%Y-%m-%d %H:%M:%S")


        payload = {
        "eform_progress" : eform.getProgress,
        # eform_progress : 100
        # "role_result" : getEformStatus(eform),
        "role_result" : get_eform_status(eform_data),
        
        ## user id 
        "done_by_id" : eform.doneby_id,
        "verify_by_id" : eform.verifiedby_id,
        "endorse_by_id" : eform.endorsedby_id,
        
        "done_by_datetime" : doneDate,
        "verify_by_datetime" : verifiedDate,
        "endorse_by_datetime" : endorsedDate,
        "is_endorse_required" : eform_data.is_endorse_required,
        }

        if eform.doneby_id is not None:
            action = "done"
            username = User.objects.get(pk=eform.doneby_id).username

        if eform.verifiedby_id is not None:
            action = "verified"
            username = User.objects.get(pk=eform.verifiedby_id).username

        if eform.endorsedby_id is not None:
            action = "endorsed"
            username = User.objects.get(pk=eform.endorsedby_id).username

        if eform.is_endorse_required == False:
            user = rot.repair_order.created_by
            if user and user.email and user.enable_email:
                logger.info("Send email to owner after endorsed{}: {}".format(username, user.email))
                
                email_template = render_to_string(
                        'emails/after_endorse_email.html',
                        {'user':user, 'rot_objs':rots, 'endorser': username, 'isIGI': rot.repair_order.mtce_type=='IGI'}
                    )
                subject = "Reminder - CEWS Eform Task In Maintenance Order"
                EmailService.emailAction(subject, user.email, '', email_template)

        repair_order_part.status = repair_order.status = check_repair_order_task(rot)

        new_log = Log(
            username= username,
            log_type=Log.LogType.MAINTENANCE,
            category_type=Log.CategoryType.TASK,
            action_type=Log.ActionType.UPDATE,
            action="handle_eform_save",
            description=f"eform task {action} by {username}",
            payload= json.dumps(payload),
            repair_order=rot.repair_order.id,
            parent_stock_code='',
            parent_part='',
            part=rot.serial_no,
            stock_code=rot.stock_code
        )
        
        with transaction.atomic():
            new_log.save()
            rot.save()
            repair_order.save()
            repair_order_part.save()
            RepairService.update_repair_order_last_action_date(rot.repair_order.id)
        
        logger.info('rot is done')
    else:
        logger.info('rot not found')

@receiver(post_delete, sender=Eform)
def eform_delete_signal(sender,instance,**kwargs):
    rot:RepairOrderTask
    rot = RepairOrderTask.objects.filter(eform_id=instance.id).first()
    if rot:
        rot.eform_id = None
        rot.done_by_datetime = None
        rot.verify_by_datetime = None
        rot.endorse_by_datetime = None
        
        rot.done_by = None
        rot.verify_by = None
        rot.endorse_by = None
        
        rot.save()
        
@receiver(eform_verify_signal)
def when_eform_verify(sender,instance:Eform,**kwargs):
    logger.info('eform verify signal received')
    handle_eform_save(instance)
    
@receiver(eform_endorse_signal)
def when_eform_endorse(sender,instance:Eform,**kwargs):
    logger.info('eform endorse signal received')
    handle_eform_save(instance)

@receiver(eform_done_signal)
def when_eform_done(sender,instance:Eform,**kwargs):
    logger.info('eform done signal received')
    handle_eform_save(instance)

@receiver(eform_save_signal)
def when_eform_save(sender,instance:Eform,**kwargs):
    logger.info('eform save signal received')
    handle_eform_save(instance)
    
@receiver(post_save,sender=StockItem) 
def after_stock_item_save(sender,instance:StockItem,created,**kwargs):
    """
        Signal to update version master, if version master not exisit, create new one
    """
    ## check is version master exisit
    vm = VersionMaster.objects.filter(stock_code=instance.stock_code).first()
    if not vm:
        create_version_master(instance)
        return 
    
    update_version_master(vm,instance)

    ## global regular cycle month同步parts
    Parts.objects.filter(stock_code=instance.stock_code, stock_item_regular_cycle_month=instance.before_global_regular_cycle_month).update(stock_item_regular_cycle_month=instance.global_regular_cycle_month)

@receiver(pre_save, sender=StockItem)
def before_stock_item_save(sender,instance:StockItem,**kwargs):
    """
        保存前将golbal_regular_cycle_month保存到before_global_regular_cycle_month
    """
    try:
        instance.before_global_regular_cycle_month = StockItem.objects.get(pk=instance.id).global_regular_cycle_month
    except StockItem.DoesNotExist:
        instance.before_global_regular_cycle_month = instance.global_regular_cycle_month
    
@receiver(post_save,sender=Parts)
def after_parts_save(sender,instance:Parts,created,**kwargs):
    
    pv = PartVersion.objects.filter(parts=instance).order_by('-id').first()
    
    if (not pv) or (pv.sw_ver != instance.sw_ver or pv.hw_ver != instance.hw_ver):
        create_part_version(instance)


@receiver(post_save,sender=RepairOrderPart)
def after_repair_order_part_create(sender,instance:RepairOrderPart,created,**kwargs):
    """
        Signal to create task for repair order part
    """
    if created:
        # tasks = create_task_for_repair_order_part(instance)
        # logger.info(tasks)
        # logger.info('tasks created')    
        create_repair_order_part_version(instance)

    if instance.before_last_check_out != instance.last_check_out:
        Parts.objects.filter(stock_code=instance.stock_code, serial_no=instance.serial_no).update(last_check_out=instance.last_check_out, last_check_in=instance.last_check_in)
        repairorder = instance.repair_order
        repairorder.last_check_out = instance.last_check_out
        repairorder.last_check_in = instance.last_check_in
        repairorder.save()

    
@receiver(pre_save, sender=RepairOrderPart)
def before_repair_order_part_update(sender,instance:RepairOrderPart,**kwargs):
    """保存此对象前保存

    Args:
        将last_check_out保存到before_last_check_out
        发送修改的时候, 同步修改其他数据
    """
    instance.before_last_check_out = instance.last_check_out

@receiver(post_save,sender=RepairOrderPartVersion)
def after_repair_order_part_version_update(sender,instance:RepairOrderPartVersion,created,**kwargs):
    """
        Signal to create task for repair order part
    """
    if created:
        return
        # tasks = create_task_for_repair_order_part(instance)
        # logger.info(tasks)
        # logger.info('tasks created')    
    rop:RepairOrderPart
    rop = instance.repair_order_part
    rop.sw_ver = instance.sw_ver
    rop.hw_ver = instance.hw_ver
    rop.save()
        

# @receiver(post_save,sender=RepairOrder)
# def after_repair_order_status_update(sender,instance:RepairOrder,created,**kwargs):
#     Rep

        
# @receiver(post_save,sender=StockItemReplacement)
# def after_stock_item_replacement_update(sender,instance:StockItemReplacement,created,**kwargs):
#     '''
#         Signal to update parts repalcement
#     '''
    
#     if created:
#         return
    
    
#     stock_code = instance.stock_item.stock_code
    
#     parts_id = Parts.objects.filter(stock_code=stock_code).values_list('id',flat=True)
    
#     parts_replacements = PartsReplacement.objects.filter(parts_id__in=parts_id,component=instance.component)
        
#     for pr in parts_replacements:
#         pr.period = instance.period
#         pr.deleted = instance.deleted
    
#     PartsReplacement.objects.bulk_update(parts_replacements,['period','deleted'])
    
#     return parts_replacements

